package com.blue.http.server;

import java.nio.charset.Charset;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.task.TaskExecutor;

import com.blue.core.dict.HttpMethod;
import com.blue.http.annotation.HttpParser;
import com.blue.http.annotation.HttpUrlMethod;
import com.blue.http.invoke.Invoker;
import com.blue.http.message.DefaultHttpRequest;
import com.blue.http.message.HttpResponse;
import com.blue.http.util.HttpException;
import com.blue.http.util.HttpServerUtil;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;

public class HttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest>
{
	private static Logger logger = LoggerFactory.getLogger(HttpServerHandler.class);

	private TaskExecutor taskExecutor;
	private Invoker invoker;
	private HttpParser httpParser;
	private long maxUploadSize;

	public HttpServerHandler(TaskExecutor taskExecutor, Invoker invoker,
			HttpParser httpParser, long maxUploadSize)
	{
		this.taskExecutor = taskExecutor;
		this.invoker = invoker;
		this.httpParser = httpParser;
		this.maxUploadSize = maxUploadSize;
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request)
			throws Exception
	{
		if (!request.decoderResult().isSuccess())
		{
			HttpServerUtil.sendError(ctx, HttpResponseStatus.BAD_REQUEST);
			return;
		}

		HttpMethod httpMethod = HttpMethod.valueOf(request.method().name());
		String ip = HttpServerUtil.getIp(request.headers(), ctx.channel());
		DefaultHttpRequest httpRequest = new DefaultHttpRequest(httpMethod, ip);
		httpRequest.parseUri(request.uri());
		HttpUrlMethod urlMethod = httpParser.getUrlMethod(httpRequest.getUrl(), httpMethod);
		if (urlMethod == null)
		{
			HttpServerUtil.sendError(ctx, HttpResponseStatus.NOT_FOUND);
			return;
		}

		if (httpMethod == HttpMethod.POST)
		{
			Charset charset = Charset.forName(urlMethod.getCharset().getName());
			try
			{
				httpRequest.parsePost(request, charset, maxUploadSize);
			}
			catch (HttpException e)
			{
				HttpServerUtil.sendError(ctx, HttpResponseStatus.REQUEST_ENTITY_TOO_LARGE);
				return;
			}
		}

		taskExecutor.execute(() ->
		{
			HttpResponse response = invoker.invoke(httpRequest);
			this.handleResponse(ctx, request, response);
		});

	}

	private void handleResponse(ChannelHandlerContext ctx, FullHttpRequest request, HttpResponse response)
	{
		if (response.getDownload() != null) // 下载文件
		{
			HttpStaticHandler.download(ctx, request, response.getDownload());
		}
		else if (response.isLocation())
		{
			HttpServerUtil.sendRedirect(ctx, response.getLocation());
		}
		else // API接口
		{
			HttpServerUtil.sendHtml(ctx, request, response);
		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
			throws Exception
	{
		super.exceptionCaught(ctx, cause);
		if (ctx.channel().isActive())
		{
			HttpServerUtil.sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
		}
	}
}
